package com.spring.theory.aop.cglibProxy;

import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

/**
 * Cglib代理类实现
 * - 基于子类继承父类的代理实现
 * - 一个代理类创建了两个FastClass做代理；避免反射
 * <p>
 * 一个方法生成使用一个代理类，一个代理类生成两个FastClass，一个配合目标使用、一个配合代理对象使用，直接避免反射
 *
 * @author H
 * @version 1.0
 * @date 2024-01-03 13:27
 */
public class CglibProxy extends CglibTarget {

    /**
     * 增强代理接口
     */
    private final MethodInterceptor methodInterceptor;

    public CglibProxy(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }

    /**
     * 带增强功能的方法
     */
    @Override
    public void test() {
        try {
            methodInterceptor.intercept(this, test, new Object[0], testProxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public int test(int i) {
        try {
            return (int) methodInterceptor.intercept(this, testInt, new Object[]{i}, testIntProxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public void test(long l) {
        try {
            methodInterceptor.intercept(this, testLong, new Object[]{l}, testLongProxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    /**
     * 原始功能的方法
     */
    public void testSuper() {
        super.test();
    }

    public int testSuper(int i) {
        return super.test(i);
    }

    public void testSuper(long l) {
        super.test(l);
    }

    static final Method test;
    static final Method testInt;
    static final Method testLong;

    static final MethodProxy testProxy;
    static final MethodProxy testIntProxy;
    static final MethodProxy testLongProxy;


    static {
        try {
            test = CglibTarget.class.getMethod("test");
            testInt = CglibTarget.class.getMethod("test", int.class);
            testLong = CglibTarget.class.getMethod("test", long.class);
            /**
             * MethodProxy创建时记录方法信息及代理类和原始类信息
             * 1：目标类型
             * 2：代理类型
             * 3：声明参数及返回值(底层使用asm解析字节码)
             *    - ()V：()标识方法参数类型；V标识方法返回类型
             * 4：带增强功能的方法名
             * 5：带原始功能的方法名
             *
             * ===内部逻辑===
             * 一个代理类创建了两个FastClass做代理；避免反射；一个配合目标使用、一个配合代理对象使用
             *
             * 内部创建了 FastClass 对象，以及方法 Signature 信息，方法信息会被记录一个 index 索引编号；
             * 调用 invoke 方法时，根据 index 索引编号，就能找到对应的方法信息，然后通过传入的目标类对象去调用对应的方法，就能避开反射调用，提升性能
             *
             * -- fastClass.invoke(index,obj,args); index就是方法签名的下标，obj是目标对象，args是参数
             *
             *
             */
            testProxy = MethodProxy.create(CglibTarget.class, CglibProxy.class, "()V", "test", "testSuper");
            testIntProxy = MethodProxy.create(CglibTarget.class, CglibProxy.class, "(I)I", "test", "testSuper");
            testLongProxy = MethodProxy.create(CglibTarget.class, CglibProxy.class, "(J)V", "test", "testSuper");
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }

}
